This project aims at providing a thought-provoking outlook on the evolution of the NBA in the 21st Century.
It takes the form of a Shiny App, with each of the following visualisations and their respective Input Variables
The document is organized in three tabs with a deep-dive on Player Performance - with 3 visualisations and a table - a breakdown of Team Performance - with 3 visualisations and a table - and a final Season Recap Visualisation.

1) NBA Players breakdown

  1. Shot Chart

Input variables :

  1. Season
  2. Player
Data and Visualisation Choices
  1. The Data

The data necessary for this visualisation was scraped from the NBA.com API, partly inspired from an Owen Phillips blog post adaptation of the {ballr} package (which proposed a function for scraping a particular dataset from the NBA.com API).

Plenty of datasets are accessible from the NBA.com API, which was the main source for the project.

For this specific visualisation, the goal was to visualise shooting volume and shooting efficiency by zone for each NBA player.

The main datasets at the source of the following visualisation are as follows :

  • {get_shot_data_player(player, season)}
    For this specific dataset, I joined the league-wide shooting volume and efficiency data to the player specific data in order to get a sense of the player’s efficiency by zone, compared to league average.
get_shot_data_player("Stephen Curry", season = "2020-21") %>% 
   rmarkdown::paged_table()
  • {get_subtitles_tbl(player, season)}
    I also gathered the traditional statistics of the player necessary for the plot subtitles (points, overall 2 point shot efficiency, overall 3 point shot efficiency)
get_subtitles_tbl("Stephen Curry", season = "2020-21") %>% 
   rmarkdown::paged_table()
  • {get_team_logo_from_player(player, season)} & {get_player_picture(player, season)}
    Finally, I created functions to get the urls for the Player Pictures and Team Logos
  1. Visualisation choices

The visualisation is inspired from Espn’s Kirk Goldsberry’s infamous shot charts, and the code for drawing the court also comes from Owen Phillips’ adaptation of the ballr package.

Instead of the tricky hexbins, I went with a shooting proficiency scatterplot with a size variable associated with volume and a fill variable associated with efficiency. In order to have more flexibility drawing the legends than using the traditional {ggplot2} API, I drew the two legends as separate ggplots, which I then added to the scatterplot using the {patchwork} package.

In order to give further visual upside to the chart, I used the {ggtext} package to plot the player pictures and team logo.

I will have to tweak the size parameter variable of the geom points, as it does not discriminate the variance in volume shooting enough in my view.

This specific instance of the visualisation is the result of the function plot_court(player = "Stephen Curry", season = "2020-21") and shows the shooting performance of Stephen Curry in the 2020-21 NBA Season. As we can see, he was both a prolific and efficient shooter this season.

  1. Specific Definitions
  • Shooting Volume : Number of shots attempted by the player in each location
  • Shooting Efficiency : Difference between the Shooting Percentage the player achieved and the League Average in each location



  1. Scoring performance analysis

Input variables :

  1. Season
  2. Team
Data and Visualisation Choices
  1. The Data

The data necessary for this visualisation was partly scraped from the NBA.com API and partly scraped from basketball-reference.

The main datasets at the source of the following visualisation are as follows :

  • {get_mean_ts_pct(season)}
    I scraped the basketball-reference website to get the League Average efficiency metric used for the following visualisation, True Shooting Percentage.
get_mean_ts_pct(season = "2020-21")
## [1] 0.572
  • {get_scoring_rate(season)}

For this specific dataset, I scraped the per-possession statistics from the NBA.com API to get the 100 best volume scorers in a specific season, as well as their shooting efficiency.

get_scoring_rate(season = "2020-21") %>% 
   rmarkdown::paged_table()

In order to speed up the r code, I used the {future} version of the {purrr}package, the {furrr} package.

  1. Visualisation choices

This visualisation is a mapping of the best scorers in the NBA in terms of volume and efficiency.

In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the geom points tooltip to add the selected player’s name, picture and relevant statistics using HTML and CSS.

This specific instance of the visualisation is the result of the function plot_scoring_rate(team = "San Antonio Spurs", season = "2020-21") and puts forth the best scorers of the 2020-21 NBA Season while highlighting the San Antonio Spurs players.

  1. Specific Definitions
  • True Shooting Percentage : A Compounded measure of a player’s efficiency taking into consideration its 2 point shot %, 3 point shot % and Free Throw % as well as the volume of each shot type
  • Scoring Rate : Points scored every 75 possessions by a player, it is a measure of a player’s scoring volume independent of the pace of a basket-ball game (meaning the number of possessions played in a game



  1. Player rankings

Input variables :

  1. Season
  2. Ranking Variable :
    • BPM (Box Plus-Minus)
    • Points
    • Assists
    • Rebounds
    • Blocks
    • Steals
Data and Visualisation Choices
  1. The Data

The data necessary for this visualisation was partly scraped from the NBA.com API and from basketball-reference.

The goal for this visualisation was to provide a ranking of the top 10 best players in each of the main statistical categories.

The main datasets at the source of the following visualisation are as follows :

  • {get_bpm_join(season)}
    I scraped the basketball-reference website in order to join an all-in-one metric designed to estimate Overall player impact, Box Plus-Minus, which has an offensive, and defensive component, to the NBA.com API-scraped player statistics.
get_bpm_join(season = "2020-21") %>% 
   rmarkdown::paged_table()
  1. Visualisation choices

This visualisation is a ranked bar chart of the 10 best NBA players in a specific statistical category, in a specific season.

In relevant instances (Box Plus-Minus and Rebounding), the offensive and defensive components of the metric are highlighted so as to put forth the statistical particularities of each player.

In order to give further visual upside to the chart, I used the {ggtext} package to plot the player pictures as axis.

In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the geom points tooltip to add the selected player’s name, picture and relevant statistics using HTML and CSS.

This specific instance of the visualisation is the result of the function plot_player_ranking_interactive(variable = "bpm", season = "2020-21") and puts forth the best players of the 2020-21 NBA Season in terms of Box Plus-Minus.

  1. Specific Definitions
  • BPM : Box Plus-Minus is an all-in-one metric that assesses a player’s value based on the player’s statistical profile as well as the results of the team while the player is on the court
  • Rebound : A rebound is performed when a player obtains the ball after a missed field goal attempt. Rebounds can be Offensive (when the player’s team missed the shot) or Defensive (when the opponent missed the shot)
  • Block : A block is performed when a player tips or deflects an opponent’s shot
  • Steal : A steal is performed when a player intercepts the ball



  1. Players table

Input variables :

  1. Season
  2. Ranking Variable :
    • BPM (Box Plus-Minus) :
      • Global
      • Offensive
      • Defensive
    • Points
    • Assists
    • Rebounds
    • Blocks
    • Steals
Data and Visualisation Choices
  1. The Data

The data necessary for this table was partly scraped from the NBA.com API, from basketball-reference, from basketball.realgm.com and from the ESPN.com website.

The goal for this table was to provide a ranking of the top 25 best players in each of the main statistical categories with a context of team performance.

The main datasets at the source of the following visualisation are as follows :

  • {get_bpm_join(season)}
    I scraped the basketball-reference website in order to join an all-in-one metric designed to estimate Overall player impact, Box Plus-Minus, which has an offensive, and defensive component, to the NBA.com API-scraped player statistics.
  • {get_playoff_teams(season)}
    I scraped the basketball-reference website in order to get a vector of the teams that qualified to the NBA Playoffs
get_playoff_teams(season = "2019-20")
##  [1] "Dallas Mavericks"       "Los Angeles Clippers"   "Utah Jazz"             
##  [4] "Los Angeles Lakers"     "Milwaukee Bucks"        "Miami Heat"            
##  [7] "Boston Celtics"         "Toronto Raptors"        "Houston Rockets"       
## [10] "Denver Nuggets"         "Orlando Magic"          "Portland Trail Blazers"
## [13] "Brooklyn Nets"          "Oklahoma City Thunder"  "Indiana Pacers"        
## [16] "Philadelphia 76ers"     "League Average"
  • {get_champion(.season)}
    I scraped the basketball-reference website in order to get the name of the NBA Champion in a particular season
get_champion(.season = "2019-20")
## [1] "Los Angeles Lakers"
  • {get_all_stars(season)}
    I scraped the basketball.realgm.com website in order to get a table of the players that were honored with a selection to the NBA All-Star Game in a particular NBA Season
get_all_stars(season = "2019-20") %>% 
   rmarkdown::paged_table()
  • {get_award(award, .season)}
    I scraped the ESPN.com website in order to get the name of the players that were honored with the main NBA Season Awards (MVP, Finals MVP…)
get_award(award = "mvp") %>% 
   rmarkdown::paged_table()
  1. Visualisation choices

This visualisation is a table of the 25 best NBA players in the selected statistical category, in a specific season.

I used the {gt} package to customize the table, but might decide to look into the {reactable} API for this visualisation in my final output, should I prefer an interactive table.

This specific instance of the visualisation is the result of the function plot_players_table(variable = "bpm", season = "2020-21") and puts forth the best players of the 2020-21 NBA Season in terms of Box Plus-Minus.

  1. Specific Definitions
  • BPM : Box Plus-Minus is an all-in-one metric that assesses a player’s value based on the player’s statistical profile as well as the results of the team while the player is on the court
  • Rebound : A rebound is performed when a player obtains the ball after a missed field goal attempt. Rebounds can be Offensive (when the player’s team missed the shot) or Defensive (when the opponent missed the shot)
  • Block : A block is performed when a player tips or deflects an opponent’s shot
  • Steal : A steal is performed when a player intercepts the ball
  • All-Star : An All-Star is a player selected to participate to the NBA All-Star Game. It is an award typically granted to the 24 best players in the NBA


Player-oriented Season Overview | 2019-20
Ranking of the 25 best players in Box Plus-Minus
Player
Position
PER GAME STATISTICS SHOOTING ACCURACY AWARDS ALL-IN-ONE METRICS POSTSEASON
Points Assists Rebounds Blocks Steals 2 Point Shooting 3 Point Shooting1 FT Shooting2 MVP DPOY3 All-Star BPM4 Offensive BPM4 Defensive BPM4 Team Playoffs Champion Finals MVP
1
Giannis Antetokounmpo
Power Forward
29.5 5.6 13.6 1.0 1.0 63.3% 30.4% 63.3%

+11.5 +7.4 +4.1
Bucks
Milwaukee

2
James Harden
Shooting Guard
34.3 7.5 6.6 0.9 1.8 55.6% 35.5% 86.5%

+9.6 +8.1 +1.6
Rockets
Houston

3
Kawhi Leonard
Small Forward
27.1 4.9 7.1 0.6 1.8 50.0% 37.8% 88.6%

+8.9 +6.5 +2.4
Clippers
Los Angeles

4
LeBron James
Point Guard
25.3 10.2 7.8 0.5 1.2 56.5% 34.8% 69.3%

+8.4 +6.6 +1.8
Lakers
Los Angeles

5
Luka Doncic
Point Guard
28.8 8.8 9.4 0.2 1.0 57.3% 31.6% 75.8%

+8.4 +7.4 +1
Mavericks
Dallas

6
Anthony Davis
Power Forward
26.1 3.2 9.3 2.3 1.5 54.2% 33.0% 84.6%

+8 +5.4 +2.6
Lakers
Los Angeles

7
Damian Lillard
Point Guard
30.0 8.0 4.3 0.3 1.1 52.9% 40.1% 88.8%

+7.5 +8.3 -0.9
Blazers
Portland Trail

8
Nikola Jokic
Center
19.9 7.0 9.7 0.6 1.2 58.9% 31.4% 81.7%

+7.4 +5.5 +2
Nuggets
Denver

9
Jimmy Butler
Small Forward
19.9 6.0 6.7 0.6 1.8 49.1% 24.4% 83.4%

+5.4 +4 +1.5
Heat
Miami

10
Paul George
Small Forward
21.5 3.9 5.7 0.4 1.4 45.2% 41.2% 87.6%
+4.9 +3.8 +1.1
Clippers
Los Angeles

11
Joel Embiid
Center
23.0 3.0 11.6 1.3 0.9 52.0% 33.1% 80.7%

+4.7 +3.7 +1
76ers
Philadelphia

12
Kemba Walker
Point Guard
20.4 4.8 3.9 0.5 0.9 48.0% 38.1% 86.4%

+4.6 +4.9 -0.3
Celtics
Boston

13
Chris Paul
Point Guard
17.6 6.7 5.0 0.2 1.6 54.8% 36.5% 90.7%

+4.4 +3 +1.4
Thunder
Oklahoma City

14
Nikola Vucevic
Center
19.6 3.6 10.9 0.8 0.9 53.3% 33.9% 78.4%
+4.2 +3.7 +0.5
Magic
Orlando

15
Khris Middleton
Small Forward
20.9 4.3 6.2 0.1 0.9 54.2% 41.5% 91.6%

+4.1 +3.4 +0.7
Bucks
Milwaukee

16
Jayson Tatum
Power Forward
23.4 3.0 7.0 0.9 1.4 47.8% 40.3% 81.2%

+4 +3.5 +0.6
Celtics
Boston

17
Trae Young
Point Guard
29.6 9.3 4.3 0.1 1.1 50.4% 36.1% 86.0%

+3.9 +6.2 -2.3
Hawks
Atlanta
18
Rudy Gobert
Center
15.1 1.5 13.5 2.0 0.8 69.5% 63.0%

+3.6 +1.7 +1.9
Jazz
Utah

19
Ben Simmons
Point Guard
16.4 8.0 7.8 0.6 2.1 58.4% 62.1%

+3.6 +1.3 +2.3
76ers
Philadelphia

20
Bam Adebayo
Power Forward
15.9 5.1 10.2 1.3 1.1 56.5% 69.1%

+3.4 +1.4 +2
Heat
Miami

21
Danilo Gallinari
Power Forward
18.7 1.9 5.2 0.1 0.7 47.5% 40.5% 89.3%
+3.3 +4.1 -0.9
Thunder
Oklahoma City

22
Domantas Sabonis
Power Forward
18.5 5.0 12.4 0.5 0.8 56.3% 25.4% 72.3%

+3.2 +2 +1.2
Pacers
Indiana

23
Kyle Lowry
Point Guard
19.4 7.5 5.0 0.4 1.4 51.7% 35.2% 85.7%

+3.2 +2.2 +1
Raptors
Toronto

24
Hassan Whiteside
Center
15.5 1.2 13.5 2.9 0.4 61.5% 68.6%
+3.2 +2.5 +0.7
Blazers
Portland Trail

25
John Collins
Power Forward
21.6 1.5 10.1 1.6 0.8 64.3% 40.1% 80.0%
+3.1 +3.7 -0.6
Hawks
Atlanta
Visualisation by Henri Freixe • Sources : Nba.com, Basketball-reference.com, Espn.com

1 Shooting Percentage among players shooting at least 0.2 Three point shots per Game

2 Free Throw Shooting

3 Defensive Player of the Year

4 Box Plus Minus estimates a player's overall contribution


2) NBA Teams breakdown

  1. Teams net rating (off vs. def.)

Input variables :

  1. Season
Data and Visualisation Choices
  1. The Data

The data necessary for this table was partly scraped from the NBA.com API and from basketball-reference.

The goal for this plot was to provide an overview of the best teams, both in terms of Offensive and Defense.

The main datasets at the source of the following visualisation are as follows :

  • {get_team_advanced(season)}
    I scraped the NBA.com API website in order to get the advanced team statistics I was looking for, namely Offensive Efficiency (which corresponds to the amount of points scored by a given team every 100 possessions) and Defensive Efficiency (which corresponds to the amount of points scored against a given team every 100 possessions)
get_team_advanced(season = "2020-21") %>% 
   rmarkdown::paged_table()
  • {get_champion(.season)}
    I scraped the basketball-reference website in order to get the name of the NBA Champion in a particular season
get_champion(.season = "2020-21") #No Champion yet in 2020-21 as the season is not over
## [1] "Milwaukee Bucks"
  1. Visualisation choices

This visualisation is a mapping of the 30 NBA teams in terms of Offensive and Defensive Efficiency. The better a given team is at Offense and Defense, the higher and to the right its position is within the mapping.

In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logos.

In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the geom points tooltip to add the selected team logo’s name and relevant statistics using HTML and CSS.

This specific instance of the visualisation is the result of the function plot_players_table(variable = "bpm", season = "2020-21") and showcases teams efficiency in the 2020-21 NBA Season.

  1. Specific Definitions
  • Offensive Efficiency : Offensive efficiency (or Offensive Rating) corresponds to the number of points scored by a team every 100 possessions. The higher the number the better the team is at offense
  • Defensive Efficiency : Defensive efficiency (or Defensive Rating) corresponds to the number of points scored against a team every 100 possessions. The lower the number the better the team is at defense



  1. Teams offensive efficiency / 3 points shooting

Input variables :

  1. League Average vs. Specific Team
Data and Visualisation Choices
  1. The Data

The data necessary for this visualisation was partly scraped from the NBA.com API and from basketball-reference.

The goal for this table was to provide an overview of the evolution of Offensive Strategy and Offensive Efficiency in the 2010s.

The main datasets at the source of the following visualisation are as follows :

  • {get_all_seas_team_shoot_split(start_season, end_season)}
    I scraped the NBA.com API in order to get the share of shots taken by each team in each zone, to see whether there was relevant conclusions to be made. It turns out, indeed, that teams traded off mid-range shots (shots taken that were neither near the rim, nor behind the three point line) for three-point shots between 2011 and 2021 mostly.
get_all_seas_team_shoot_split() %>% 
   rmarkdown::paged_table()
  • {bbal_ref_rating(start_season, end_season, team)}
    I scraped the basketball-reference website in order to get the Offensive Efficiency (also called Offensive Rating) for each team, each season, between 2011 and 2021. It turns out the average Offensive Efficiency kept rising between 2011 and 2021.
bbal_ref_rating() %>% 
   rmarkdown::paged_table()
  1. Visualisation choices

This visualisation is a parallel line chart and bar chart of the evolution of average offensive efficiency on the one hand, and of the share of shots taken that are three point shots on the other hand. It turns out that trading off mid-range shots for three point shots correlates nicely with offensive efficiency.

In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the outlying geom points tooltip to add the selected team’s name and relevant statistic using HTML and CSS.

I also used the {patchwork} package to show merge charts in the same visualisation.

In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logo.

In order to speed up the r code, I used the {future} version of the {purrr}package, the {furrr} package.

There is also a team argument to this function, so as to show the selected team’s offensive efficiency evolution, on top of the League Average and outliers (season-highs and season-lows) on the one hand, and the selected team’s shooting split evolution on the other hand.

This specific instance of the visualisation is the result of the function plot_off_evo_interactive(team = "global") and showcases League Average offensive efficiency and shooting split evolution from 2011-2012 until 2020-2021.

  1. Specific Definitions
  • Offensive Efficiency : Offensive efficiency (or Offensive Rating) corresponds to the number of points scored by a team every 100 possessions. The higher the number the better the team is at offense
  • Mid-range shots : Mid-range shots are shots that are neither worth 3 points nor near the basket. While they are typically scored at a higher percentage than 3 point shots since they are shorter-ranged, they typically yield much lower value in terms of efficiency as the percentage difference does not make-up for the difference in value



  1. Teams Bumpchart

Input variables :

  1. Season
  2. Team
  3. Variable
    • Salary
    • Offensive Efficiency
    • Defensive Efficiency
Data and Visualisation Choices
  1. The Data

The data necessary for this visualisation was partly scraped from the NBA.com API, from basketball-reference and from hoopshype.com.

The goal for this visualisation was to explore the correlation between Team Performance (represented by Win Percentage) with given variables (roster salary, offensive efficiency or defensive efficiency for example).

The main datasets at the source of the following visualisation are as follows :

  • {get_team_standings(season)}
    I scraped the NBA.com website in order to get the Team Standings, to get the Win/Loss record for each team in a given season.
get_team_standings(season = "2020-21") %>% 
   rmarkdown::paged_table()
  • {get_salaries(season)}
    I scraped the hoopshype.com website in order to get a table of the roster salary for each team in a given season.
get_salaries(season = "2020-21") %>% 
   rmarkdown::paged_table()
  • {bballref_efficiency_season(season)} & {bballref_def_efficiency_season(season)}
    I scraped the basketball-reference website in order to get each team’s offensive and defensive efficiency in a given season.
bballref_efficiency_season(season = "2020-21") %>% 
   rmarkdown::paged_table()
bballref_def_efficiency_season(season = "2020-21") %>% 
   rmarkdown::paged_table()
  1. Visualisation choices

This visualisation is a bump chart of teams ranked by Win Percentage, and a specific variable (salary, off. efficiency or def. efficiency) in a given season, with a spotlight on the selected team.

In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logo.

This specific instance of the visualisation is the result of the function plot_bump_chart(season = "2020-21", variable = "salary",team = "Phoenix Suns") and explores the relationship between Win Percentage and Salary in the 2020-21 NBA Season. The Phoenix Suns look like the team that achieved the most from the least amount of salary roster.

  1. Specific Definitions
  • Offensive Efficiency : Offensive efficiency (or Offensive Rating) corresponds to the number of points scored by a team every 100 possessions. The higher the number the better the team is at offense
  • Defensive Efficiency : Defensive efficiency (or Defensive Rating) corresponds to the number of points scored against a team every 100 possessions. The lower the number the better the team is at defense



  1. Teams table

Input variables :

  1. Season
  2. Conference
Data and Visualisation Choices
  1. The Data

The data necessary for this table was partly scraped from the NBA.com API, from basketball-reference, from basketball.realgm.com and from the ESPN.com website.

The goal for this table was to highlight the ranking of each team of a given Conference in a given season.

The main datasets at the source of the following visualisation are as follows :

  • {get_team_standings(season)}& {get_team_advanced_selections(season)} &{get_traditional_stats(season)}
    I scraped the NBA.com website in order to get the Team Standings (in particular the Win/Loss record for each team in a given season), the Advanced Team Statistics (in particular Efficiency and other per possession based metrics) and Player Statistics (in order to highlight the scoring statistics of the leading scorer for each NBA team).
get_team_advanced_selections(season = "2019-20") %>% 
   rmarkdown::paged_table()
  • {get_playoff_teams(season)}
    I scraped the basketball-reference website in order to get a vector of the teams that qualified to the NBA Playoffs
##  [1] "Dallas Mavericks"       "Los Angeles Clippers"   "Utah Jazz"             
##  [4] "Los Angeles Lakers"     "Milwaukee Bucks"        "Miami Heat"            
##  [7] "Boston Celtics"         "Toronto Raptors"        "Houston Rockets"       
## [10] "Denver Nuggets"         "Orlando Magic"          "Portland Trail Blazers"
## [13] "Brooklyn Nets"          "Oklahoma City Thunder"  "Indiana Pacers"        
## [16] "Philadelphia 76ers"     "League Average"
  • {get_champion(season)}
    I scraped the basketball-reference website in order to get the name of the NBA Champion in a particular season
## [1] "Los Angeles Lakers"
  • {get_all_stars(season)}
    I scraped the basketball.realgm.com website in order to get a table of the players that were honored with a selection to the NBA All-Star Game in a particular NBA Season
get_all_stars(season = "2019-20") %>% 
   rmarkdown::paged_table()
  1. Visualisation choices

This visualisation is a table ranking of the NBA teams in terms of Win Percentage, in a given conference, in a given season.

I used the {gt} package to customize the table, but might decide to look into the {reactable} API for this visualisation in my final output, should I prefer an interactive table.

This specific instance of the visualisation is the result of the function plot_teams_table("2019-20", conf = "West") and gives thought-provoking information about teams from the Western Conference in the 2019-20 NBA Season.

  1. Specific Definitions
  • Offensive Efficiency : Offensive efficiency (or Offensive Rating) corresponds to the number of points scored by a team every 100 possessions. The higher the number the better the team is at offense
  • Defensive Efficiency : Defensive efficiency (or Defensive Rating) corresponds to the number of points scored against a team every 100 possessions. The lower the number the better the team is at defense
  • Net rating : The net rating is the difference between Offensive Efficiency and Defensive Efficiency. The higher the number the higher the overall value of the team
  • All-Star : An All-Star is a player selected to participate to the NBA All-Star Game. It is an award typically granted to the 24 best players in the NBA


Season Overview Western Conference | 2019-20
Top 8 teams in each Conference to qualify for the playoffs
Team
Record
TEAM RESULTS ROSTER STANDOUTS POSTSEASON
Win Percentage Offensive Efficiency1 Defensive Efficiency1 Net Rating All-Stars2 Leading Scorer Playoffs Champion
1

↑+9

Lakers Los Angeles
52-19
73.2% 111.7 106.1 +5.6

★★

Davis
26.1 pts per game

2

↑+6

Clippers Los Angeles
49-23
68.1% 113.3 106.9 +6.3

Leonard
27.1 pts per game

3

↓-1

Nuggets Denver
46-27
63.0% 112.6 110.4 +2.2

Jokic
19.9 pts per game

4

Rockets Houston
44-28
61.1% 112.5 109.8 +2.7

★★

Harden
34.3 pts per game

5

↑+1

Thunder Oklahoma City
44-28
61.1% 110.1 108.1 +2.1

Gilgeous-Alexander
19 pts per game

6

↓-1

Jazz Utah
44-28
61.1% 111.8 109.3 +2.5

★★

Mitchell
24 pts per game

7

↑+7

Mavericks Dallas
43-32
57.3% 115.9 111.2 +4.8

Doncic
28.8 pts per game

8

↓-5

Blazers Portland Trail
35-39
47.3% 113.2 114.3 -1.1

Lillard
30 pts per game

9

↑+3

Grizzlies Memphis
34-39
46.6% 108.7 109.7 -1
Morant
17.8 pts per game
10

↑+5

Suns Phoenix
34-39
46.6% 111.3 110.8 +0.5

Booker
26.6 pts per game
11

↓-4

Spurs San Antonio
32-39
45.1% 111.7 112.6 -0.9
DeRozan
22.1 pts per game
12

↓-3

Kings Sacramento
31-41
43.1% 109.5 111.4 -1.9
Fox
21.1 pts per game
13

Pelicans New Orleans
30-42
41.7% 110.5 111.8 -1.3

Ingram
23.8 pts per game
14

↓-3

Timberwolves Minnesota
19-45
29.7% 107.6 111.6 -4
Russell
23.1 pts per game
15

↓-14

Warriors Golden State
15-50
23.1% 104.4 113.0 -8.6
Wiggins
21.8 pts per game
Visualisation by Henri Freixe • Sources : Nba.com, Basketball-reference.com, Basketball.realgm.com,Espn.com

1 Efficiency corresponds to the number of points scored / allowed every 100 possessions

2 Number of players to participate in the 2019-20 NBA All-Star Game


3) Season recap plot

Input variable :

  1. Season
Data and Visualisation Choices
  1. The Data

The data necessary for this table was partly scraped from the NBA.com API, from basketball-reference, from basketball.realgm.com and from the ESPN.com website.

The goal for this table was to provide an Overview of the main events of the selected NBA Season, looking into the NBA Finals, the NBA All-Star Game and the winners of the main NBA Awards.

The main datasets at the source of the following visualisation are as follows :

  • {get_finals_stats(season)}
    I scraped the NBA.com website in order to get the result for all games in a specific NBA Finals, in order to visually represent the way the NBA Finals playet out. As a reminder, the NBA Finals are a series between the winner of each Conference, in a Best Of 4 Games match-up, meaning the first team to win 4 games in the series wins the NBA Finals.
get_finals_stats(season = "2018-19") %>% 
   rmarkdown::paged_table()
  • {get_award_stats(award, .season)}
    I scraped the basketball-reference website in order to get the relevant statistics for the recipient of a given NBA Award in a given Season (MVP, Finals MVP, Sixth Man of the Year, Defensive Player of the Year, Most Improved Player or Rookie of the Year).
## # A tibble: 1 x 6
##   player_name           team    pts   reb   ast award
##   <chr>                 <chr> <dbl> <dbl> <dbl> <chr>
## 1 Giannis Antetokounmpo MIL    27.7  12.5   5.9 mvp
  • {get_all_stars(season)}
    I scraped the basketball.realgm.com website in order to get a table of the players that were honored with a selection to the NBA All-Star Game in a particular NBA Season
get_all_stars(season = "2018-19") %>% 
   rmarkdown::paged_table()
  • `{get_traditional_stats(season)}
    I scraped the NBA.com website in order to get the Player Statistics (in order to add the All-Stars season statistics as tooltip information).
get_traditional_stats(season = "2018-19") %>% 
   rmarkdown::paged_table()
  1. Visualisation choices

This visualisation regroups three different visualisations and aims at providing a visual overview of a given NBA Season. The three combined visualisations are a scatterplotted lollipop plot that highlights the outcome of the NBA Finals, a text plot providing statistical insights about the recipients of the main NBA Awards and an interactive facetted scatterplot about the NBA All-Stars.

In order to get a more complete picture of the situation, I used the {ggiraph} package to customize the All-Stars geom points tooltip to add the selected player’s team name and relevant statistic using HTML and CSS.

In order to give further visual upside to the chart, I used the {ggtext} package to plot the team logos and player pictures.

The {patchwork} package was used to combine the three visualisations.

In order to speed up the r code, I used the {future} package to run the three plotting functions in parallel.

This specific instance of the visualisation is the result of the function plot_season_recap(season = "2020-21") and provides a deep-dive into the 2020-21 NBA Season.

  1. Specific Definitions
  • All-Star : An All-Star is a player selected to participate to the NBA All-Star Game. It is an award typically granted to the 24 best players in the NBA.
  • Sixth Man of the Year : Sixth Man of the Year is an award granted to the player perceived as the best among players who start the game off the bench.
  • Rookie of the Year : Rookie of the Year is an award granted to the player perceived as the best among new players.



Email     LinkedIn     Twitter     Github

A Project by Henri Freixe as part of the EPFL Applied Data Science Communication & Visualisation Certificate of Open Studies
Sources: nba.com, espn.com, basketball-reference.com, basketball.realgm.com, hoopshype.com